package com.itheima.d0_feedback.feedback2;

import org.junit.Test;

import java.lang.annotation.*;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;

/*
元注解中的Target注解中定义的注解位置，顺序有什么要求嘛，为什么打乱了就不能运行出来？
（比如：要定义类型和字段使用元注解，在定义元注解Target的时候先定义类型或者先定义字段，顺序不同会存在错误嘛）
-------------诺克萨斯，永世长存
   如果自己定义的注解需要再反射时解析到，必须要定义生命周期能到达RUNTIME

练测 注解：注解的解析parseClass()方法，解析类上的所有注解，获得类上的所有注解，再遍历注解数组，判断遍历到的注解是MyTest还是Service，
再使用class.getDeclaredAnnotation(Mytest.class/Service.class)方法获取注解对象。
这种方式拓展性太差，想要解析其他的注解还要再加代码。有没有简单的实现方式？
    可以把解析的动作封装为工具方法，操作简单了。

在遍历注解数组的时候，调用注解对象的toString()方法，可以将对象内的属性名与值都打印出来，toString是如何做到的
    JDK在定义注解类型的时候，会自动生成。


解释下：当访问一个静态域时，只有真正声明这个域的类才会被初始化，
例子：当通过子类引用父类的静态变量，不会导致子类初始化。
【类的加载过程】
https://blog.csdn.net/Strange_boy/article/details/125717606


导致类的初始化：
1. 实例化一个类
2. 使用到类的静态字段
3. 反射操作类也会进行初始化
。。。。

 */

class Fu {
    static String str1 = "Fu str";

    static {
        System.out.println("Fu 类正在初始化");
    }
}


class Demo2 {
    public static void main(String[] args) throws ClassNotFoundException {
        //Class<Fu> cls = Fu.class;
        //System.out.println(Fu.str1);
        //new Fu();
        //Class.forName("feedback2.Fu");


        System.out.println("执行完毕！！");
    }
}


@Ano1
public class Demo01 {
    //@Ano1("哈哈")
    public void test() {
    }


    @Test()
    public void parseAno1() {
       /* Class<Demo01> cls = Demo01.class;
        if (cls.isAnnotationPresent(Ano1.class)) {
            System.out.println("存在");

            Ano1 ano = cls.getDeclaredAnnotation(Ano1.class);
            String value = ano.value();
            System.out.println("value = " + value);

        } else {
            System.out.println("不存在");
        }*/

        Class<Demo01> cls = Demo01.class;
        //解析的注解Anno1
        Ano1 ann = (Ano1) parseAnnotation(cls, Ano1.class);
        System.out.println(ann.value());
    }


    @Test
    public void parseMethod() throws NoSuchMethodException {
        //1 获取类字节码对象
        Class<Demo01> cls = Demo01.class;
        //2 反射获取方法对象
        Method testMethod = cls.getDeclaredMethod("test");
      /*  //3 判断是否存在注解
        if (testMethod.isAnnotationPresent(Ano1.class)) {
            //4 获取注解对象
            Ano1 ano1 = testMethod.getDeclaredAnnotation(Ano1.class);
            System.out.println(ano1.value());
        }*/

        Ano1 an = (Ano1) parseAnnotation(testMethod, Ano1.class);
        if (an == null) {
            System.out.println("没有注解");
        } else {
            System.out.println(an.value());
        }

    }

    public static Annotation parseAnnotation(AnnotatedElement element, Class anno) {
        if (element.isAnnotationPresent(anno)) {
            Annotation an = element.getAnnotation(anno);
            return an;
        }
        return null;
    }
}

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface Ano1 {
    String value() default "我是注解";
}

